每天的專案會同步到 GitLab 上,可以前往 GitLab 查看。
有興趣的朋友歡迎留言 or 來信討論,我的信箱是 nickchen1998@gmail.com。
在昨天的結尾當中,我們有提到 LangChain 中的 Chain,今天我們就來看一下 Chain 的語法該怎麼寫。
延續昨天的文章,如果們要進行更加複雜的查詢,就必須要把資料表的詳細資訊一併傳遞給 LLM,這樣 LLM 才可以協助我們寫出更加完善的查詢語法。
而在 LangChain 當中,當然也幫我們寫好了一個方法讓我們可以直接使用,讓我們看一下下面的範例:
from langchain.chains import create_sql_query_chain
from env_settings import EnvSettings
from langchain_openai import ChatOpenAI
from langchain_community.utilities import SQLDatabase
env_settings = EnvSettings()
llm = ChatOpenAI(
api_key=env_settings.OPENAI_API_KEY,
model_name="gpt-4o"
)
db = SQLDatabase.from_uri("sqlite:///./test.db")
create_query = create_sql_query_chain(db=db, llm=llm)
print(create_query.invoke({"question": "請問 Alice 買了什麼東西?"}))
在這個範例當中,我們使用了 create_sql_query_chain
這個方法,這個方法會幫我們建立一個 Chain,
這個 Chain 會將我們的問題傳遞給 LLM 並且透過資料庫的資訊來產生 SQL 語句,
這樣我們就可以直接透過這個 Chain 來取得我們想要的 SQL 語句,然而我們可以看一下下方的執行結果:
可以看到在執行結果中,我們成功的取得了我們想要的 SQL 語句,不過這個語句還是有一些問題,我們需要去除一些雜訊,因此我們寫了這個小 function:
import re
def clean_sql_query(query):
sql_query = query.replace("```sql\n", "").replace("\n```", "").strip().replace("\n", " ")
pattern = r'SELECT.*'
match = re.search(pattern, sql_query, re.DOTALL | re.IGNORECASE)
return match.group() if match else sql_query
接著就是要將我們的兩個動作串連起來了,在 LangChain 當中,不同的兩個動作,我們稱為 Operator,有學過 Airflow 的朋友應該會很眼熟,
沒錯,在 LangChain 當中同樣也可以使用類似於 Airflow 的語法來進行撰寫,讓我們看一下下面的範例:
import re
from langchain.chains import create_sql_query_chain
from env_settings import EnvSettings
from langchain_openai import ChatOpenAI
from langchain_community.utilities import SQLDatabase
from langchain_community.tools import QuerySQLDataBaseTool
def clean_sql_query(query):
sql_query = query.replace("```sql\n", "").replace("\n```", "").strip().replace("\n", " ")
pattern = r'SELECT.*'
match = re.search(pattern, sql_query, re.DOTALL | re.IGNORECASE)
return match.group() if match else sql_query
env_settings = EnvSettings()
llm = ChatOpenAI(
api_key=env_settings.OPENAI_API_KEY,
model_name="gpt-4o"
)
db = SQLDatabase.from_uri("sqlite:///./test.db")
create_query = create_sql_query_chain(db=db, llm=llm)
execute_query = QuerySQLDataBaseTool(db=db)
chain = create_query | clean_sql_query | execute_query
print(chain.invoke({"question": "請問 Alice 買了什麼東西?"}))
可以看到我們透過 |
這個符號將三個 Operator 串連起來,這樣我們就可以直接透過 chain.invoke
來執行我們的 Chain,
其中 execute_query
這個參數是我們昨天有提到的 QuerySQLDataBaseTool
,這個 Tool 會將 SQL 語句傳遞給資料庫進行操作,
下面來看一下我們的執行結果:
在查詢出我們要的資料後,我們要將資料連同原始的問題一起傳遞給 LLM 進行回答,這時候我們就需要取得前面 Operator 的參數,
我們可以使用 itemgetter
這個方法來取得,讓我們看一下下面的範例:
import re
from langchain.chains import create_sql_query_chain
from env_settings import EnvSettings
from langchain_openai import ChatOpenAI
from langchain_community.utilities import SQLDatabase
from langchain_community.tools import QuerySQLDataBaseTool
from langchain_core.prompts import ChatPromptTemplate
from operator import itemgetter
def clean_sql_query(query):
sql_query = query.replace("```sql\n", "").replace("\n```", "").strip().replace("\n", " ")
pattern = r'SELECT.*'
match = re.search(pattern, sql_query, re.DOTALL | re.IGNORECASE)
return match.group() if match else sql_query
env_settings = EnvSettings()
llm = ChatOpenAI(
api_key=env_settings.OPENAI_API_KEY,
model_name="gpt-4o"
)
db = SQLDatabase.from_uri("sqlite:///./test.db")
create_query = create_sql_query_chain(db=db, llm=llm)
execute_query = QuerySQLDataBaseTool(db=db)
search_template = ChatPromptTemplate.from_template(
"""
原始問題: {question}
取得的參考資料: {data}
""",
)
chain = (
{
"data": create_query | clean_sql_query | execute_query,
"question": itemgetter("question")
}
| search_template
| llm
)
ai_message = chain.invoke({"question": "請問 Alice 買了什麼東西?"})
print(ai_message.content)
可以看到在範例當中,我們在第一個 operator 中使用了 itemgetter
來取得 question
這個參數,並且將查詢資料的 chain 寫在 data 這個參數裡面,
這樣我們就可以直接將查詢出的資料作為參數提供給後面的 operator 進行使用。
下面我們看一下執行結果:
可以看到在執行結果中,我們成功的取得了我們想要的回答,表示在 search_template 當中有成功使用到我們定義的 data
以及 question
這兩個參數。
針對串接語言模型以及 LangChain 基本語法及概念的部分,我們就暫時介紹到這邊,明天開始我們會進入到 Embedding、RAG 以及如何使用 LangChain 來進行問答系統的開發。